package com.freewater.cargotracker.domain.model.cargo;

import com.freewater.cargotracker.domain.common.Value;
import com.freewater.cargotracker.domain.model.location.Location;
import org.apache.commons.lang3.Validate;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * 航程（航海日程）：<br/>
 * 货物从出发地到目的地，途中需要换乘多个航线才能到达；
 */
public class Itinerary implements Serializable, Value {

    private static final long serialVersionUID = 1L;

    public static final Itinerary EMPTY_ITINERARY = new Itinerary();

    private List<Leg> legs = Collections.emptyList();

    public Itinerary() {

    }

    public Itinerary(List<Leg> legs) {
        Validate.notNull(legs, "Legs are required");
        Validate.noNullElements(legs, "Leg can not be null");
        this.legs = legs;
    }

    public Location getInitialDepartureLocation() {
        if (legs.isEmpty()) {
            return Location.UNKNOWN;
        }
        return legs.get(0).getLoadLocation();
    }

    public Location getFinalArrivalLocation() {
        if (legs.isEmpty()) {
            return Location.UNKNOWN;
        }
        return getLastLeg().getUnloadLocation();
    }

    public LocalDateTime getFinalArrivalDateTime() {
        final Leg lastLeg = getLastLeg();
        if (lastLeg == null) {
            return LocalDateTime.MAX;
        }
        return lastLeg.getUnloadTime();
    }

    public List<Leg> getLegs() {
        return Collections.unmodifiableList(legs);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Itinerary)) return false;
        Itinerary itinerary = (Itinerary) o;
        return sameValueAs(itinerary);
    }

    @Override
    public int hashCode() {
        return Objects.hash(legs);
    }

    @Override
    public String toString() {
        return "Itinerary{" +
                "legs=" + legs +
                '}';
    }

    private boolean sameValueAs(Itinerary other) {
        return other != null && other.legs.equals(legs);
    }

    private Leg getLastLeg() {
        if (legs.isEmpty()) {
            return null;
        }
        return legs.get(legs.size() - 1);
    }
}
